package com.wuwen.ai.extension.neo4j;

import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.dbms.api.DatabaseManagementServiceBuilder;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
import org.neo4j.io.ByteUnit;

import java.nio.file.Path;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Neo4jService {
    public static final String AI_EXTENSION_GRAPH_DB = "AIExtensionGraphDb";
    private final GraphDatabaseService db;
    private static Neo4jService INSTANCE;

    private Neo4jService(GraphDatabaseService db) {
        this.db = db;
    }

    public static Neo4jService INSTANCE() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        synchronized (Neo4jService.class) {
            if (INSTANCE != null) {
                return INSTANCE;
            }
            DatabaseManagementService managementService =
                    new DatabaseManagementServiceBuilder(Path.of("target/graph.db"))
                            .setConfig(GraphDatabaseSettings.pagecache_memory, ByteUnit.mebiBytes(512))
                            .setConfig(GraphDatabaseSettings.transaction_timeout, Duration.ofSeconds(60))
                            .setConfig(GraphDatabaseSettings.preallocate_logical_logs, true)
                            .build();
            // 检查数据库是否存在
            List<String> dbs = managementService.listDatabases();
            if (dbs == null || dbs.isEmpty()) {
                managementService.createDatabase(AI_EXTENSION_GRAPH_DB);
            }
            managementService.startDatabase(AI_EXTENSION_GRAPH_DB);
            Runtime.getRuntime().addShutdownHook(new Thread(managementService::shutdown));
            INSTANCE = new Neo4jService(managementService.database(AI_EXTENSION_GRAPH_DB));
            return INSTANCE;
        }
    }

    public void addNeo4J() {
        
        System.out.println("Database Load!");
        try (Transaction tx = db.beginTx()) {
            Node n1 = tx.createNode();
            n1.setProperty("name", "张三");
            n1.setProperty("character", "A");
            n1.setProperty("gender", 1);
            n1.setProperty("money", 1101);
            n1.addLabel(() -> "Person");
        }
        String cql = "CREATE (p:Person{name:'李四',character:'B',gender:1,money:21000})";
        System.out.println("Database Shutdown!");
    }

    public void queryNeo4JAll() {
        String cql = "MATCH (a:Person) where a.money < $money return a";
        Map<String, Object> params = new HashMap<>();
        params.put("money", 25000);
        try (Transaction tx = db.beginTx()) {
            Result result = tx.execute(cql, params);
            while (result.hasNext()) {
                Map<String, Object> row = result.next();
                for (String key : result.columns()) {
                    Node nd = (Node) row.get(key);
                    System.out.printf("%s = %s:%s%n", key,
                            nd.getProperty("name"), nd.getProperty("money"));
                }
            }
        }
    }
}
